﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mnk.Merger.Code.Common;
using Mnk.Merger.Code.Settings;

namespace Mnk.Merger.Code.Repository
{
    class RepositoryCache : IRepositoryCache, IDisposable
    {
        private readonly IRepositoryProvider repositoryProvider;
        private readonly IJsonDataSerializer serializer;
        private readonly MergeConfig config;
        private readonly IDictionary<string, IList<SvnLogEntry>> cache = 
            new Dictionary<string, IList<SvnLogEntry>>();
        private readonly IDictionary<string, string> aliases;

        public RepositoryCache(IRepositoryProvider repositoryProvider, IJsonDataSerializer serializer, MergeConfig config)
        {
            this.repositoryProvider = repositoryProvider;
            this.serializer = serializer;
            this.config = config;
            aliases = serializer.Load(BuildConfigPath(), new Dictionary<string, string>());
        }

        public IList<SvnLogEntry> Get(string url, string folder)
        {
            var endpoint = BuildUri(url, folder);
            IList<SvnLogEntry> items;
            if (cache.TryGetValue(endpoint, out items))
            {
                return items;
            }
            string alias;
            string path;
            if (aliases.TryGetValue(url, out alias))
            {
                path = BuildPath(alias, folder);
                if (File.Exists(path))
                {
                    items = serializer.Load<IList<SvnLogEntry>>(path);
                    cache[endpoint] = items;
                    return items;
                }
            }
            else
            {
                alias = Guid.NewGuid().ToString();
                path = BuildPath(alias, folder);
                aliases[url] = alias;
            }
            items = repositoryProvider.Collect(endpoint);
            serializer.Save(path, items);
            cache[endpoint] = items;
            return items;
        }

        public IList<SvnLogEntry> Get(string url)
        {
            var uri = new Uri(url);
            var folder = uri.Segments.Last();
            return Get(url.Replace("/" + folder, ""), folder);
        }

        public void Update()
        {
            if (Directory.Exists(config.CacheFolder))
            {
                Directory.Delete(config.CacheFolder,true);
            }
            aliases.Clear();
        }

        private static string BuildUri(string url, string folder)
        {
            if (!url.EndsWith("/")) url += "/";
            return url + folder;
        }

        private string BuildPath(string alias, string folder)
        {
            var path = Path.Combine(config.CacheFolder, alias);
            if (!Directory.Exists(path)) Directory.CreateDirectory(path);
            if (!string.IsNullOrEmpty(config.MergeFrom))
            {
                folder += "." + config.MergeFrom;
            }
            return Path.Combine(path, folder + ".json");
        }

        private string BuildConfigPath()
        {
            if (!Directory.Exists(config.CacheFolder)) Directory.CreateDirectory(config.CacheFolder);
            return Path.Combine(config.CacheFolder, "settings.json");
        }

        public void Dispose()
        {
            if (aliases.Any())
            {
                serializer.Save(BuildConfigPath(), aliases);
            }
        }
    }
}
